package com.example.esjdsearch.service;

import com.example.esjdsearch.pojo.Content;
import com.example.esjdsearch.utils.HtmlParseUtil;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Created by bothin
 * At 2020/4/11 12:03
 * Description:
 */
@Service
public class ContentService {
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 从京东抓取数据放入elasticsearch中
     *
     * @param keyword
     * @return
     * @throws Exception
     */
    public Boolean addJdData(String keyword) throws Exception {
        List<Content> list = HtmlParseUtil.getJdData(keyword);
        List<IndexQuery> queries = new ArrayList<>();

        list.forEach(e -> {
            IndexQuery indexQuery = new IndexQueryBuilder().withObject(e).build();
            queries.add(indexQuery);
        });

        this.elasticsearchRestTemplate.bulkIndex(queries);
        return true;
    }

    public AggregatedPage<Content> searchForPage(String keyword, int page, int pageSize) {
        if (page < 1) {
            page = 1;
        }

        SearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchQuery("title", keyword)) // match查询
                .withPageable(PageRequest.of(page-1,pageSize))
                .withHighlightBuilder(new HighlightBuilder().field("title"))
                .build();

        AggregatedPage<Content> contents = this.elasticsearchRestTemplate.queryForPage(query, Content.class,
                new SearchResultMapper() {
                    @Override
                    public <T> AggregatedPage<T> mapResults(SearchResponse response,
                                                            Class<T> clazz, Pageable pageable) {
                        List<T> result = new ArrayList<>();
                        if (response.getHits().totalHits == 0) {
                            return new AggregatedPageImpl<>
                                    (Collections.emptyList(), pageable, 0L);
                        }
                        for (SearchHit searchHit : response.getHits()) {
                            // 通过反射写入数据到对象中
                            T obj = (T) ReflectUtils.newInstance(clazz);

                            try {
                                //如果对象中有id属性，则写入id
                                if (FieldUtils.getField(clazz, "id", true) != null) {
                                    FieldUtils.writeField(obj, "id", searchHit.getId(), true);

                                }
                                // 处理非高亮字段
                                for (Map.Entry<String, Object> entry : searchHit.getSourceAsMap().entrySet()) {
                                    //跳过对象中没有的字段
                                    Field field = FieldUtils.getField(clazz, entry.getKey(), true);
                                    if (null == field) {
                                        continue;
                                    }

                                    FieldUtils.writeField(obj, entry.getKey(), entry.getValue(), true);
                                }
                                // 处理高亮字段
                                for (Map.Entry<String, HighlightField> entry : searchHit.getHighlightFields().entrySet()) {
                                    //跳过对象中没有的字段
                                    Field field = FieldUtils.getField(clazz, entry.getKey(), true);
                                    if (null == field) {
                                        continue;
                                    }

                                    Text[] fragments = entry.getValue().fragments();
                                    StringBuilder sb = new StringBuilder();
                                    for (Text fragment : fragments) {
                                        sb.append(fragment.toString());
                                    }
                                    FieldUtils.writeField(obj, entry.getKey(), sb.toString(), true);
                                }
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
                            result.add(obj);
                        }
                        return new AggregatedPageImpl<>(result, pageable, response.getHits().totalHits);
                    }

                    @Override
                    public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
                        return null;
                    }
                });

        return contents;
    }

}
